package com.myblog.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myblog.constant.EmailConstant;
import com.myblog.constant.MessageConstant;
import com.myblog.constant.RedisConstant;
import com.myblog.constant.UserConstant;
import com.myblog.entity.Users;
import com.myblog.entity.dto.LoginDTO;
import com.myblog.entity.dto.UserDTO;
import com.myblog.entity.vo.UserVO;
import com.myblog.mapper.UsersMapper;
import com.myblog.service.IUsersService;
import com.myblog.utils.TokenUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 沙琪马
 * @since 2024-06-21
 */
@Slf4j
@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements IUsersService {

    @Resource
    JavaMailSender javaMailSender;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 注册用户
     *
     * @param user
     */
    @Override
    public void registerUsers(UserDTO user) {
        // 1.判断用户是否已被创建
        // 1.1.构建通过用户名查询条件
        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Users::getEmail, user.getEmail());
        if (getOne(wrapper) != null) {
            throw new RuntimeException(EmailConstant.EMAIL_EXIST);
        }
        // 1.2.从redis取出验证码，判断是否过期
        if (Boolean.TRUE.equals(redisTemplate.hasKey(RedisConstant.REDIS_KEY_PREFIX + user.getEmail()))) {
            String code = (String) redisTemplate.opsForValue().get(RedisConstant.REDIS_KEY_PREFIX + user.getEmail());
            if (code != null && code.equals(user.getVerificationCode())) {
                // 1.2.1.验证码正确，删除redis中的验证码
                redisTemplate.delete(RedisConstant.REDIS_KEY_PREFIX + user.getEmail());
            }else{
                throw new RuntimeException(MessageConstant.VERIFICATION_CODE_ERROR);
            }
        }else{
            throw new RuntimeException(MessageConstant.VERIFICATION_CODE_EXPIRED);
        }
        // 2.保存用户信息
        // 2.1.用户信息更替
        Users users = new Users();
        BeanUtils.copyProperties(users, user);
        save(users);
    }

    /**
     * 发送邮件
     *
     * @param email
     */
    public void sendVerificationCode(String email) {
        // 1.构建邮件对象
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(EmailConstant.EMAIL_FORMAT); // 发送方
        simpleMailMessage.setTo(email); // 接收方
        simpleMailMessage.setSubject(EmailConstant.EMAIL_SUBJECT); // 标题
        String code = RandomUtil.randomNumbers(EmailConstant.VERIFICATION_CODE_LENGTH);// 随机一个 4位长度的验证码
        // 2.将验证码保存到redis中
        redisTemplate.opsForValue().set(RedisConstant.REDIS_KEY_PREFIX + email, code, EmailConstant.EMAIL_EXPIRE_TIME, TimeUnit.MINUTES);
        simpleMailMessage.setSentDate(new Date()); // 设置发送时间
        // TODO 邮箱登录和注册发送内容有点问题
        simpleMailMessage.setText("您本次邮箱登录的验证码是:" + code + ",有效时间为"+EmailConstant.EMAIL_EXPIRE_TIME+EmailConstant.EMAIL_EXPIRE_TIME_UNIT+".请妥善保管,切勿泄露."); // 内容
        // 3.发送邮件
        javaMailSender.send(simpleMailMessage);
        log.info("邮件:" + email + ",发送成功");
    }

    /**
     * 用户名登录
     * @param loginDTO
     */
    public UserVO loginByUsername(LoginDTO loginDTO) {
        // 1.根据用户名查询用户信息
        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Users::getUsername, loginDTO.getUsername())
                .eq(Users::getPassword, loginDTO.getPassword());
        // 1.1.查询用户信息，如果为空，说明登录异常
        Users one = getOne(wrapper);
        if (one == null) {
            throw new RuntimeException(UserConstant.USERNAME_OR_PASSWORD_ERROR);
        }
       return login(one);
    }

    /**
     * 邮箱登录
     * @param loginDTO
     * @return
     */
    @Override
    public UserVO loginByEmail(LoginDTO loginDTO) {
        // 1.根据用户名查询用户信息
        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Users::getEmail, loginDTO.getEmail());
        // 1.1.查询用户信息，如果为空，说明登录异常
        Users one = getOne(wrapper);
        if (one == null) {
            throw new RuntimeException(EmailConstant.EMAIL_NOT_EXIST);
        }
        // 2.验证码验证
        // 2.1.获取redis中的验证码
        String code = (String)redisTemplate.opsForValue().get(RedisConstant.REDIS_KEY_PREFIX + loginDTO.getEmail());
        // 2.2.判断验证码是否正确
        if (code != null && code.equals(loginDTO.getVerificationCode())) {
            // 2.2.1.验证码正确，删除redis中的验证码
            redisTemplate.delete(RedisConstant.REDIS_KEY_PREFIX + loginDTO.getEmail());

            return login(one);
        }else{
            throw new RuntimeException(UserConstant.VERIFICATION_CODE_ERROR);
        }
    }

    /**
     * 登录，生成token，存于redis中
     * @param one
     * @return UserVO
     */
    public UserVO login(Users one){
        // 2.生成token
        String token = TokenUtils.createToken(one.getId().toString(), one.getUsername());
        // 2.1.缓存token
        redisTemplate.opsForValue().set(RedisConstant.REDIS_KEY_PREFIX_USER+one.getId().toString(), token, UserConstant.LOGIN_TIME, TimeUnit.MINUTES);

        // 3.封装数据
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(one, userVO);

        return userVO;
    }
}
